//
//  IVWEngine.m
//  AIKITDemo
//
//  Created by xyzhang on 2023/3/16.
//
// initSDK -> delegate -> loadData -> preProcess -> specifyDataSet -> [start -> write -> end] -> uninit

#import "IVWEngine.h"
#import "IFlyDebugLog.h"

@interface IVWEngine ()<AIKitCoreDelegate>
{
    int _keywordIndex;
}

@property (nonatomic, copy) NSString *abilityId;

@property (nonatomic, strong) AiHandle *handle;

/// 唤醒词沙盒路径
@property (nonatomic, copy) NSString *wakeupWordsPath;

/// 判断是否识别到唤醒词
@property (nonatomic, assign) BOOL isWoken;

@end

@implementation IVWEngine

- (instancetype)init {
    if (self = [super init]) {
        
    }
    return self;
}

- (void)setConfig:(IFlyIVWConfig *)config {
    self.ivwConfig = config;
    _abilityId = config.abilityId;
}

#pragma mark - 唤醒接口

- (int)startEngine {
    [IFlyDebugLog showLog:@"%s, [IN]", __func__];
    
    @synchronized(self){
        //session begin
        int retCode = 0;
        
        [self storeWakeupWords];
        retCode = [self loadWakeupWords];
        if ( retCode == NO ) {
            [IFlyDebugLog showLog:@"%s, [OUT], loadWakeupWords error", __func__];
            return 20010; // 唤醒词加载失败 error code 20xxx
        }
        
        AIKITParameters *params = [[AIKITParameters alloc] init];
        [params addString:@"wdec_param_nCmThreshold" value:[_ivwConfig getMultipleThresholdString]];
        [params addBool:@"gramLoad" value:[_ivwConfig.gramLoad boolValue]];
        
        [IFlyDebugLog showLog:@"%s, AiHelper start [IN] handle:%@", __func__, self.handle];
        self.handle = [AiHelper start:_abilityId param:params ctxContent:nil];
        [IFlyDebugLog showLog:@"%s, AiHelper start [OUT] handle:%@", __func__, self.handle];
        
        if (!self.handle.isSuccess) {
            [IFlyDebugLog showLog:@"%s, [OUT], handle.code=%lu", __func__, _handle.code];
            return (int)_handle.code; // error code 18xxx
        } else {
            // 注册代理
            [AiHelper registerAbilityCallback:self.abilityId callback:self];
        }
        
    }
    
    [IFlyDebugLog showLog:@"%s, [OUT]", __func__];
    
    return 0;
}


- (void)stopEngine {
    [IFlyDebugLog showLog:@"stopEngine [IN]"];
    
    @synchronized(self){
        
        if (self.handle) {
            int endErrorCode = [AiHelper end:self.handle];
            if (endErrorCode) {
                [IFlyDebugLog showLog:@"stopEngine [OUT], errorCode:%d", __func__, endErrorCode];
            } else {
                // success
            }
            
        } else {
            [IFlyDebugLog showLog:@"stopEngine [OUT], self.handle is nil!"];
        }
        
    }
        
    [IFlyDebugLog showLog:@"stopEngine [OUT]"];
}

/// 写入音频数据
/// - Parameters:
///   - buffer: 音频缓冲
///   - length: 音频长度
///   - audioStatus: 0-Begin 1-Continue 2-End 3DataStatusOnce
- (int)writeAudio:(const void*)buffer length:(unsigned int)length audioStatus:(int)audioStatus {
    
//    [IFlyDebugLog showLog:@"%s [IN], length=%i, audioStatus:%i", __func__, length, audioStatus];
    @synchronized (self) {
        
        NSData *inputData = [NSData dataWithBytes:buffer length:length];
        
        AIKITInputData *inputs = [[AIKITInputData alloc] init];
        [inputs addAudio:inputData key:@"wav" status:audioStatus];
        
        int retCode = [AiHelper write:inputs handle:self.handle];
        if (retCode) {
            [self.delegate onWakeupEngineRunEndDelegate:retCode];
            [IFlyDebugLog showLog:@"%s [OUT], write error:%i", __func__, retCode];
            return retCode;
        }
        
        retCode = [AiHelper read:self.handle];
        if (retCode) {
            [self.delegate onWakeupEngineRunEndDelegate:retCode];
            [IFlyDebugLog showLog:@"%s [OUT], read error:%i", __func__, retCode];
            return retCode;
        }
    }
    
//    [IFlyDebugLog showLog:@"%s [OUT]", __func__];
    return 0;
}
/*
 dispatch_async(dispatch_get_main_queue(), ^{
     
 });
 */

#pragma mark 加载唤醒词

/// 保存设置的唤醒词
- (void)storeWakeupWords {
    NSString *text = _ivwConfig.wakeupWords;
    
    [IFlyDebugLog showLog:@"%s, wakeup words:%@", __func__, _ivwConfig.wakeupWords];
    
    if (text.length <= 0) {
        text = IFlyWakeup_words_default;
    }
    
    text = [text stringByReplacingOccurrencesOfString:@"，" withString:@","];
    NSArray *wakeupWords = [text componentsSeparatedByString:@","];
    NSError *error;
    
    // $$$$$
    NSFileManager *manager = [NSFileManager defaultManager];
    NSString *dirPath = [NSHomeDirectory() stringByAppendingString:@"/Documents/wakeupWord/"];
    NSString *filePath = [NSHomeDirectory() stringByAppendingString:@"/Documents/wakeupWord/wakeupWord.txt"];
    BOOL isDir = true;
    if (![manager fileExistsAtPath:dirPath isDirectory:&isDir]) {
        [manager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:&error];
    }
    if (error) {
        return;
    }
    NSString * keywordStrings = [[wakeupWords componentsJoinedByString:@";\n"] stringByAppendingString:@";"];
    
    BOOL success = false;
    if ([manager fileExistsAtPath:filePath]) {
        success = [[keywordStrings dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePath atomically:true];
    } else {
        success = [manager createFileAtPath:filePath contents:[keywordStrings dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
    }
    if (success) {
        self.wakeupWordsPath = filePath;
    }
}

//static int _keywordIndex = 0;
- (BOOL)loadWakeupWords {
    
    log(@"加载唤醒词...");
    if (self.wakeupWordsPath.length > 0) {
        
        AIKITCustomData *customData = [[AIKITCustomData alloc] init];

        [customData addTextPath:self.wakeupWordsPath key:@"key_word" index:0];
        
        int ret = [AiHelper loadData:_abilityId data:customData];
        if (ret) {
            log(@"加载唤醒词失败code:%d",ret);
            return NO;
        } else {
            log(@"加载唤醒词完成");
        }
        
        int indexes[] = {0};
        
        ret = [AiHelper specifyDataSet:_abilityId key:@"key_word" indexs:indexes count:1];
        if (ret) {
            log(@"IVW specifyDataSet fail! code:%d",ret);
            return NO;
        } else {
            log(@"IVW specifyDataSet success!");
        }
    }
    
    // 唤醒词每次加载，index++
    if (self.wakeupWordsPath.length > 0) {
//        _keywordIndex ++;
    }
    
    return YES;
}

#pragma mark AIKitCoreDelegate

- (void)aikitOnResult:(NSString *)ability handleId:(NSInteger)handleId outputData:(NSArray<AIKITDataModel *> *)data usrCtx:(AIKITCtxContent *)context {

    _isWoken = true;
    NSMutableString *printString = [NSMutableString string];
    for (AIKITDataModel *model in data) {
        NSString *value = [NSString stringWithUTF8String:model.value];
        NSString *result = [NSString stringWithFormat:@"result:{key:%@,value:%@}",model.key,value];
        [printString appendString:result];
    }
    
    if (_delegate && [_delegate respondsToSelector:@selector(onWakeupEngineGetResultDelegate:)]) {
        [_delegate onWakeupEngineGetResultDelegate:printString];
    }
    
    [IFlyDebugLog showLog:@"%@", printString];
}

- (void)aikitOnError:(NSString *)ability handleId:(NSInteger)handleId error:(AIKITError *)error usrCtx:(AIKITCtxContent *)context {
    
    [IFlyDebugLog showLog:@"error:{code:%d,type:%d,desc:%@}",error.code,error.type,error.desc];
    
    if (_delegate && [_delegate respondsToSelector:@selector(onWakeupEngineRunEndDelegate:)]) {
        [_delegate onWakeupEngineRunEndDelegate:error.code];
    }
}
/*
 AIKIT_EVENT_UNKNOWN  = 0,
 AIKIT_EVENT_START    = 1,
 AIKIT_EVENT_END      = 2,
 AIKIT_EVENT_TIMEOUT  = 3,
 AIKIT_EVENT_PROGRESS = 4
 */
- (void)aikitOnEvent:(NSString *)ability handleId:(NSInteger)handleId event:(NSInteger)event eventData:(NSArray<AIKITDataModel *> *)data usrCtx:(AIKITCtxContent *)context {
    switch (event) {
        case AIKIT_EVENT_UNKNOWN:
            {
                
            }
            break;
        case AIKIT_EVENT_START:
            {
                [IFlyDebugLog showLog:@"AIKIT_EVENT_START"];
            }
            break;
        case AIKIT_EVENT_END:
            {
                [IFlyDebugLog showLog:@"AIKIT_EVENT_END"];
                // 等待识别结果
                if (_delegate && [_delegate onWakeupEngineStopAndWaitResultDelegate]) {
                    [_delegate onWakeupEngineStopAndWaitResultDelegate];
                }
            }
            break;
        case AIKIT_EVENT_TIMEOUT:
            {
                [IFlyDebugLog showLog:@"AIKIT_EVENT_END"];
                if (_delegate && [_delegate respondsToSelector:@selector(onWakeupEngineRunEndDelegate:)]) {
                    [_delegate onWakeupEngineRunEndDelegate:20008]; //SPEECH_ERROR_SPEECH_TIMEOUT
                }
            }
            break;
        case AIKIT_EVENT_PROGRESS:
            {
                // 处理中
                [IFlyDebugLog showLog:@"AIKIT_EVENT_END"];
            }
            break;
        default:
            break;
    }
}

@end
